package com.docmgmt.mvp.controller;

import com.docmgmt.mvp.dto.*;
import com.docmgmt.mvp.entity.FileEntity;
import com.docmgmt.mvp.entity.FolderEntity;
import com.docmgmt.mvp.entity.UserFavoriteEntity;
import com.docmgmt.mvp.exception.BusinessException;
import com.docmgmt.mvp.exception.NotFoundException;
import com.docmgmt.mvp.exception.UnauthorizedException;
import com.docmgmt.mvp.mapper.FileMapper;
import com.docmgmt.mvp.mapper.FolderMapper;
import com.docmgmt.mvp.mapper.UserFavoriteMapper;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Favorite Management Controller
 *
 * @author Dora
 */
@Slf4j
@RestController
@RequestMapping("/api/v1/favorites")
@RequiredArgsConstructor
public class FavoriteController {

    private final UserFavoriteMapper favoriteMapper;
    private final FileMapper fileMapper;
    private final FolderMapper folderMapper;

    /**
     * 4.6.1 Add Favorite
     *
     * POST /api/v1/favorites
     */
    @PostMapping
    @Transactional(rollbackFor = Exception.class)
    public Result<FavoriteVO> addFavorite(@Valid @RequestBody AddFavoriteRequest request) {
        Long userId = getCurrentUserId();

        log.info("POST /api/v1/favorites - userId={}, resourceType={}, resourceId={}",
                userId, request.getResourceType(), request.getResourceId());

        // Check if already favorited
        UserFavoriteEntity existing = favoriteMapper.selectByUserAndResource(
                userId, request.getResourceType(), request.getResourceId());
        
        if (existing != null) {
            throw new BusinessException("Already in favorites");
        }

        // Verify resource exists
        if ("file".equals(request.getResourceType())) {
            FileEntity file = fileMapper.selectById(request.getResourceId());
            if (file == null) {
                throw new NotFoundException("File not found");
            }
        } else if ("folder".equals(request.getResourceType())) {
            FolderEntity folder = folderMapper.selectById(request.getResourceId());
            if (folder == null) {
                throw new NotFoundException("Folder not found");
            }
        } else {
            throw new BusinessException("Invalid resource type");
        }

        // Create favorite
        UserFavoriteEntity favorite = UserFavoriteEntity.builder()
                .userId(userId)
                .resourceType(request.getResourceType())
                .resourceId(request.getResourceId())
                .createdAt(LocalDateTime.now())
                .build();

        favoriteMapper.insert(favorite);

        log.info("Favorite added: id={}", favorite.getId());

        return Result.success("Added to favorites successfully", entityToVO(favorite));
    }

    /**
     * 4.6.2 Remove Favorite
     *
     * DELETE /api/v1/favorites
     */
    @DeleteMapping
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> removeFavorite(
            @RequestParam String resourceType,
            @RequestParam Long resourceId) {
        Long userId = getCurrentUserId();

        log.info("DELETE /api/v1/favorites - userId={}, resourceType={}, resourceId={}",
                userId, resourceType, resourceId);

        int deleted = favoriteMapper.deleteByUserAndResource(userId, resourceType, resourceId);

        if (deleted == 0) {
            throw new NotFoundException("Favorite not found");
        }

        log.info("Favorite removed");

        return Result.success("Removed from favorites successfully");
    }

    /**
     * 4.6.3 List My Favorites
     *
     * GET /api/v1/favorites/my
     */
    @GetMapping("/my")
    public Result<List<FavoriteVO>> listMyFavorites(
            @RequestParam(required = false) String resourceType) {
        Long userId = getCurrentUserId();

        log.info("GET /api/v1/favorites/my - userId={}, resourceType={}", userId, resourceType);

        List<UserFavoriteEntity> favorites;
        
        if (resourceType != null && !resourceType.isEmpty()) {
            favorites = favoriteMapper.listByUserAndType(userId, resourceType);
        } else {
            // Query all favorites (both files and folders)
            List<UserFavoriteEntity> fileFavorites = favoriteMapper.listByUserAndType(userId, "file");
            List<UserFavoriteEntity> folderFavorites = favoriteMapper.listByUserAndType(userId, "folder");
            favorites = new ArrayList<>();
            favorites.addAll(fileFavorites);
            favorites.addAll(folderFavorites);
        }

        List<FavoriteVO> result = favorites.stream()
                .map(this::entityToVO)
                .collect(Collectors.toList());

        return Result.success("Query successful", result);
    }

    /**
     * Entity to VO
     */
    private FavoriteVO entityToVO(UserFavoriteEntity entity) {
        FavoriteVO vo = FavoriteVO.builder()
                .id(entity.getId())
                .userId(entity.getUserId())
                .resourceType(entity.getResourceType())
                .resourceId(entity.getResourceId())
                .createdAt(entity.getCreatedAt() != null ?
                        entity.getCreatedAt().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) : null)
                .build();

        // Load resource details
        if ("file".equals(entity.getResourceType())) {
            FileEntity file = fileMapper.selectById(entity.getResourceId());
            if (file != null) {
                vo.setResourceName(file.getFileName());
                // Set file details if needed
            }
        } else if ("folder".equals(entity.getResourceType())) {
            FolderEntity folder = folderMapper.selectById(entity.getResourceId());
            if (folder != null) {
                vo.setResourceName(folder.getName());
                // Set folder details if needed
            }
        }

        return vo;
    }

    /**
     * Get current user ID from Spring Security context
     */
    private Long getCurrentUserId() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new UnauthorizedException("Not logged in or authentication expired");
        }

        Object principal = authentication.getPrincipal();
        if (principal instanceof Long) {
            return (Long) principal;
        }

        throw new UnauthorizedException("Invalid authentication information");
    }
}
